﻿ using System;
using System.Collections.Generic;
using System.Text;

using PostSharp.Laos;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
using System.Reflection;

namespace EntlibAOP.Caching
{
    [Serializable]
    [AttributeUsage(AttributeTargets.Method)]


    public sealed class CacheAttribute : OnMethodInvocationAspect
    {
        /// <summary>
        /// This string will store the key to the cached object
        /// </summary>
        private string cacheKey;
        private string methodName;

        private bool matchParameter;
        

        #region Constructor
        /// <summary>
        /// Constructor takes the key as a parameter and assign it to the private
        /// variable cacheKey
        /// </summary>
        /// <param name="key">Key to access the cached object</param>
        public CacheAttribute(string key)
        {
            this.cacheKey = key;
        }

        #endregion

        #region Properties
        /// <summary>
        /// Key to access the cached object
        /// </summary>
        public string CacheKey
        {
            get
            {
                return cacheKey;
            }
        }

        public bool MatchParameter
        {
            get
            {
                return matchParameter;
            }
            set
            {
                matchParameter = value;
            }
        }
        #endregion

        #region Overloaded Methods

        public override void CompileTimeInitialize(MethodBase method)
        {
            base.CompileTimeInitialize(method);
            methodName = method.DeclaringType.Name + "." + method.Name;
        }
        /// <summary>
        /// This is the interceptor method that will implement the caching feature
        /// </summary>
        /// <param name="context">This contain the information about the method to be invoked</param>
        public override void OnInvocation(MethodInvocationEventArgs context)
        {
            if (string.IsNullOrEmpty(cacheKey))
            {
                cacheKey = methodName;
            }
            object returnValue = null;
            CacheManager cacheManager = CacheFactory.GetCacheManager();
            if (matchParameter)
            {
                string paramString = null;
                object[] args = context.GetArgumentArray();
                foreach (object arg in args)
                {
                    paramString += arg.ToString();
                }
                paramString += cacheKey;
                if (!cacheManager.Contains(paramString))
                {
                    // Populate the cache if the value is not present in the cache
                    returnValue = context.Delegate.DynamicInvoke(context.GetArguments());
                    cacheManager.Add(paramString, returnValue);
                }
                else
                {
                    returnValue = cacheManager.GetData(paramString);
                }
            }
            else
            {

                if (!cacheManager.Contains(cacheKey))
                {
                    // Populate the cache if the value is not present in the cache
                    returnValue = context.Delegate.DynamicInvoke(context.GetArguments());
                    cacheManager.Add(cacheKey, returnValue);
                }
                else
                {
                    returnValue = cacheManager.GetData(cacheKey);
                }
            }

            context.ReturnValue = returnValue;
        }
        #endregion
    }
}
